﻿//----------------------------------------------------------------------------
// Copyright (c) Pavel Tishkin 2012-2013.
//
// You must not remove this notice, or any other, from this software.
//----------------------------------------------------------------------------

namespace Lib.Dxp.Core



module Convert =

    let inline unboxOrDefault(o : obj) : 'a = 
        match o with 
        | null | :? System.DBNull  -> Unchecked.defaultof<'a> 
        | _     -> unbox o


    let inline toIntOrZero  (o : 'a) = try int o with _ -> 0


    /// "yyyy-MM-dd"
    let [<Literal>] private DATE_ISO        = "yyyy-MM-dd"
    /// "yyyyMMddhhmmss"
    let [<Literal>] private DATETIMESOLID   = "yyyyMMddHHmmss"
    /// "HH:mm:ss"
    let [<Literal>] private TIME24_ISO      = "HH:mm:ss"



    /// Functions for format strings in F# way ----------------------------------------------
    let DATETIME_ISO            = sprintf "%s-%s-%s %s:%s:%s"
    let TIME_MISS               = sprintf "%02i:%02i"
    let TIME_ISO                = sprintf "%i:%02i:%02i"
    //let private F2                      = sprintf "%.2f"                // sprintf "%15.2f" (1.0/3.0)  == right padded 
    //let private F4                      = sprintf "%.4f"                




    // ------------------------------------------------------------------------------------------------------
    module Date = 


        let private rgx = System.Text.RegularExpressions.Regex(@"[\s\-\/:\.]", System.Text.RegularExpressions.RegexOptions.Compiled)


        ///<summary>Convert System.DateTime to "yyyy-MM-dd"
        /// <para><c> := yyyymmddhhmiss2iso  datetime </c></para> </summary>
        ///<param name="datetime">Data/Time</param>
        // ------------------------------------------------------------------------------------------
        let toYYYYMMDD ( datetime : System.DateTime )  = datetime.ToString(DATE_ISO)

        let fromYYYYMMDDHHMISS (s : string) =
            System.DateTime.ParseExact(s, "yyyyMMddHHmmss", null)


        let fromString (text : string) =
            let hx = rgx.Split(text)
            let hx = if hx.Length < 6 then Array.append hx (Array.create (6 - hx.Length) "00") else hx
            match hx.[2].Length with
            | 4 -> System.DateTime(int hx.[2], int hx.[1], int hx.[0]) // from dd.mm.yyyy
            | _ -> System.DateTime(int hx.[0], int hx.[1], int hx.[2]) // from yyyy.mm.dd


        ///<summary>Convert System.DateTime to "yyyyMMddHHmmss"
        /// <para><c> := toSolidText  datetime </c></para> </summary>
        ///<param name="datetime">Data/Time</param>
        // ------------------------------------------------------------------------------------------
        let toSolidText( datetime : System.DateTime )  = datetime.ToString(DATETIMESOLID)


        ///<summary>Convert ("yyyymmddhhmiss" : string) to "yyyy-mm-dd hh:mi:ss". Right padded by 0 if need
        /// <para><c> := yyyymmddhhmiss2iso  text </c></para> </summary>
        ///<param name="text">Text</param>
        // ------------------------------------------------------------------------------------------
        let yyyymmddhhmiss2iso(text : string) = 
            match text with 
            | null | "" -> ""
            | _ -> 
            let x = if text.Length < 14 then text + String.init (14 - text.Length) (_toConst "0") else text
            DATETIME_ISO x.[0..3] x.[4..5] x.[6..7] x.[8..9] x.[10..11] x.[12..13]

        
        ///<summary>Convert `text` as ("yyyy?mm?dd?hh?mi?ss" | "dd?mm?yyyy?hh?mi?ss" : string) to "yyyy-mm-dd hh:mi:ss". Right padded by 0 if need 
        /// <para><c> := datetime2iso  text </c></para> </summary>
        ///<param name="text">Text</param>
        // ------------------------------------------------------------------------------------------
        let datetime2iso (text : string) = 
            let hx = rgx.Split(text)
            let hx = if hx.Length < 6 then Array.append hx (Array.create (6 - hx.Length) "00") else hx
            match hx.[2].Length with
            | 4 -> DATETIME_ISO hx.[2] hx.[1] hx.[0] hx.[3] hx.[4] hx.[5] // from dd.mm.yyyy
            | _ -> DATETIME_ISO hx.[0] hx.[1] hx.[2] hx.[3] hx.[4] hx.[5] // from yyyy.mm.dd



    // ------------------------------------------------------------------------------------------------------
    module Time = 

        ///<summary>Convert System.DateTime to "HH:mm:ss"
        /// <para><c> := toHHMISS  datetime </c></para> </summary>
        ///<param name="datetime">Any object</param>
        // ------------------------------------------------------------------------------------------
        let toHHMISS ( datetime : System.DateTime )    = datetime.ToString(TIME24_ISO)

        /// Convert (seconds : Numeric<>) to "mi:ss" | "hh:mi:ss"
        //  when 'a : (static member op_Explicit : 'a -> string)
        let inline seconds2hhmiss(seconds : 'a) = 
            let seconds_ = int seconds
            match seconds_ / 60 with
            | mi when mi < 60   -> TIME_MISS mi (seconds_ - mi * 60)
            | mi                -> let hh = mi / 60 
                                   TIME_ISO hh (mi - hh * 60) (seconds_ - mi * 60)

        let private rgx = System.Text.RegularExpressions.Regex(@"[\s\-\/:\.]", System.Text.RegularExpressions.RegexOptions.Compiled)

        let fromString (text : string) =
            let hx = rgx.Split(text)
            let hx = if hx.Length < 6 then Array.append hx (Array.create (6 - hx.Length) "00") else hx
            match hx.[2].Length with
            | _ -> let t = System.TimeSpan(hours = int hx.[0], minutes = int hx.[1], seconds = int hx.[2]) // from yyyy.mm.dd
                   t

